#pragma once
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <mutex>
#include <string>
#include <regex>
#include <functional>
#include "../message/interface/MessageInterface.hpp"


/**
 *
 *
 * @tparam TYPE 消息格式
 */
template<typename TYPE>
class MessagePoolsTool {
private:

    /**
     * 消息对象池
     */
    class MessageObjectPool {

    private:

        TYPE m_messageTYpe;

        std::queue<MessageInterface<TYPE>*> m_unusedPool;
        std::unordered_set<MessageInterface<TYPE>*> m_usedPool;
        std::mutex m_mutex;


        // 使用函数工厂来创建消息对象
        std::function<MessageInterface<TYPE>*()> m_creaObjectFun;

        int m_poolSize;

    private:
        /**
         *
         * @param quantity
         */
        void addMessageToPool(int quantity) {

            for (int i = 0; i < quantity; i++)
                this->m_unusedPool.emplace(this->m_creaObjectFun());
        }

    public:
        /**
         *
         * @param creaObjectFun
         * @param poolSize
         */
        MessageObjectPool(const std::function<MessageInterface<TYPE>*()>& creaObjectFun ,int poolSize = 20) {

            this->m_creaObjectFun = creaObjectFun;

            //先创建一个实例获取格式
            MessageInterface<TYPE>* message = this->m_creaObjectFun();
            this->m_messageTYpe = message->getType();
            //将创建的实例加入池中
            this->m_unusedPool.push(message);

            this->m_poolSize = poolSize;


            //初始化池由于已经将一个实例加入池中所以数量-1
            this->addMessageToPool(poolSize-1);
        }


        ~MessageObjectPool() {
            while (!this->m_unusedPool.empty()) {
                MessageInterface<TYPE>* messageObject = this->m_unusedPool.front();
                this->m_unusedPool.pop();
                delete messageObject;
            }

            for (auto& message : this->m_usedPool) {
                MessageInterface<TYPE>* messageObject = message;
                this->m_usedPool.erase(message);
                delete messageObject;
            }

        }


        /**
         *
         * @return
         */
        MessageInterface<TYPE>* acquireMessgeObject() {

            std::unique_lock<std::mutex> lock(this->m_mutex);

            //消息池已分配完，扩容消息池
            if (this->m_unusedPool.empty()) {
                int quantity = this->m_poolSize*0.5;
                this->addMessageToPool(quantity);
                this->m_poolSize+=quantity;
            }

            MessageInterface<TYPE>* message = this->m_unusedPool.front();
            this->m_unusedPool.pop();
            this->m_usedPool.insert(message);

            return message;
        }

        /**
         *
         * @param messageObject
         */
        void releaseMessageObeject(MessageInterface<TYPE>* messageObject) {
            std::unique_lock<std::mutex> lock(this->m_mutex);
            this->m_usedPool.erase(messageObject);
            this->m_unusedPool.push(messageObject);
        }

    };

private:

    //检测消息格式的正则表达式
    static const std::regex checkMessagePattern;
    //提取键值对的表达式
    static const std::regex KVPattern;
    std::unordered_map<TYPE,std::shared_ptr<MessageObjectPool>> m_messagesObjectsPools;

    int m_defaultPoolSize;

public:

    /**
     *
     * @param defaultPoolSize
     * @return
     */
    MessagePoolsTool(int defaultPoolSize = 20) {
        this->m_defaultPoolSize = defaultPoolSize;
    }


    ~MessagePoolsTool() {

    }


    /**
     *从池中获取消息实例
     * @tparam MESSAGE
     * @param messageStr
     * @param messagePointer
     * @return true分配成功 flase分配失败
     */
    template<typename MESSAGE>
    bool acquireMessge(std::string& messageStr, MESSAGE*& messagePointer) {

        if (!std::regex_search(messageStr,MessagePoolsTool<TYPE>::checkMessagePattern))
            return false;

        //提取键值对
        auto wordsBegin = std::sregex_iterator(messageStr.begin(),messageStr.end(),MessagePoolsTool<TYPE>::KVPattern);
        auto wordsEnd = std::sregex_iterator();
        std::unordered_map<std::string, std::string> keyValuePairs;
        for (std::sregex_iterator it = wordsBegin; it!=wordsEnd; ++it) {
            std::smatch match = *it;
            keyValuePairs[match[1]] = match[2];
        }

        //没有type键值对
        auto keyValuePairsIt = keyValuePairs.find("type");
        if (keyValuePairsIt == keyValuePairs.end()) return false;


        try {
            TYPE messageType = static_cast<TYPE>(std::stoi(keyValuePairsIt->second)); //调用该函数有异常可能

            //超出消息样式范围
            if (messageType >= TYPE::END || messageType <= TYPE::BEGIN)
                return false;

            //寻找该类型的消息数组
            auto messagesObjectsPoolsIt = this->m_messagesObjectsPools.find(messageType);



            //不存在该类型消息池，则创建该类型消息池
            if (messagesObjectsPoolsIt == this->m_messagesObjectsPools.end()) {
                // 使用正确的模板参数创建MessageObjectPool
                auto createMessageObjectFun = []() {
                    return new MESSAGE();
                };
                auto pool = std::make_shared<MessageObjectPool>(createMessageObjectFun,this->m_defaultPoolSize);
                messagesObjectsPoolsIt = this->m_messagesObjectsPools.emplace(messageType, pool).first;
            }


            //从池中获取Message
            MessageInterface<TYPE>* messageObject = messagesObjectsPoolsIt->second-> acquireMessgeObject();

            //将MessageObject类型转化成指定的消息类型
            messagePointer = static_cast<MESSAGE*>(messageObject);

            //通过键值对初始化消息
            messagePointer->initializetionByKeyValuePairs(keyValuePairs);

            std::cout << messagePointer << std::endl;

            return true;
        }

        catch(const std::logic_error e) {
            return false;
        }
    }


    /**
     *释放消息
     * @tparam MESSAGE
     */
    template<typename MESSAGE>
    void releaseMessage(MESSAGE* messagePointer) {
        auto messagesObjectsPoolsIt = this->m_messagesObjectsPools.find(messagePointer->getType());

        if (messagesObjectsPoolsIt == this->m_messagesObjectsPools.end()) return;

        //清除数据
        messagePointer->clear();

        messagesObjectsPoolsIt->second.get()->releaseMessageObeject(messagePointer);
    }

};

template<typename TYPE>
const std::regex MessagePoolsTool<TYPE>::checkMessagePattern = std::regex(R"(^\s*\{\s*[^\s;:]+\s*:\s*[^;:]+(?:\s*;\s*[^\s;:]+\s*:\s*[^;:]+)*\s*\}\s*$)");

template<typename TYPE>
const std::regex MessagePoolsTool<TYPE>::KVPattern = std::regex(R"(([^\s;:{]+)\s*:\s*([^;}]+)\s*)");